package com.blyat.xsoft.gateway.ribbon.router;

import com.google.common.collect.Lists;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.cloud.gateway.support.NotFoundException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.function.Function;

/**
 * @Auther: syh
 * @Date: 2020/8/21
 * @Description:
 */
public abstract class AbstractRouteDefinitionRepository implements ApplicationContextAware, RouteDefinitionRepository,
        ApplicationEventPublisherAware, InitializingBean {

    protected ApplicationContext context;
    protected ApplicationEventPublisher publisher;
    protected RouteDefinitionLoader loader;
    private Function<ApplicationContext, ? extends RouteDefinitionLoader> applier;
    private List<RouteDefinition> routeDefinitions = Lists.newArrayListWithExpectedSize(10);

    public AbstractRouteDefinitionRepository(Function<ApplicationContext, ? extends RouteDefinitionLoader> applier) {
        this.applier = applier;
    }

    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        return Flux.fromIterable(routeDefinitions);
    }

    @Override
    public Mono<Void> save(Mono<RouteDefinition> route) {
        return Mono.defer(() -> Mono.error(new NotFoundException("Unsupported operation")));
    }

    @Override
    public Mono<Void> delete(Mono<String> routeId) {
        return Mono.defer(() -> Mono.error(new NotFoundException("Unsupported operation")));
    }

    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        this.context = context;
        this.loader = this.applier.apply(context);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        this.routeDefinitions = this.loader.load();
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }

    public void setRouteDefinitions(List<RouteDefinition> routeDefinitions) {
        this.routeDefinitions = routeDefinitions;
    }
}
